package com.systop.common.modules.security.user.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.acegisecurity.providers.encoding.PasswordEncoder;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.rbcs.flow.FlowConstants;
import com.systop.common.modules.dept.model.Dept;
import com.systop.common.modules.security.user.UserConstants;
import com.systop.common.modules.security.user.dao.UserDao;
import com.systop.common.modules.security.user.model.Permission;
import com.systop.common.modules.security.user.model.User;
import com.systop.common.modules.security.user.model.UserLoginHistory;
import com.systop.common.modules.security.user.service.listener.UserChangeListener;
import com.systop.core.ApplicationException;
import com.systop.core.Constants;
import com.systop.core.service.BaseGenericsManager;

/**
 * 用户管理类
 * 
 * @author Sam Lee, Nice
 */
@Service
public class UserManager extends BaseGenericsManager<User> {

	/** 用于加密密码 */
	@Autowired
	private PasswordEncoder passwordEncoder;

	/** User对象持久化操作监听器，可以直接注入UserListener的实例 或完整的类名。 */
	private List<UserChangeListener> userChangeListeners;

	@Autowired
	public void setUserChangeListeners(List<UserChangeListener> listeners) {
		this.userChangeListeners = listeners;
	}

	@Autowired
	private UserDao userDao;

	/**
	 * 获得部门
	 * 
	 * @param id
	 * @return
	 */
	private Dept getDept(Integer id) {
		return getDao().get(Dept.class, id);
	}

	/** 保存用户 */
	@Transactional
	public void save(User user) {
		save(user, true);
	}

	/**
	 * 保存用户并关联指定的部门
	 * 
	 * @param user
	 * @param deptId
	 */
	@Transactional
	public void save(User user, Integer deptId) {
		if (deptId != null) {
			user.setDept(getDept(deptId));
		}
		save(user, true);
	}

	/**
	 * 支持密码加密的用户保存
	 * 
	 * @param user
	 * @param encode
	 */
	@Transactional
	public void save(User user, boolean encode) {

		if (user.getId() == null && user.getStatus() == null) { // 新建用户的状态为正常
			user.setStatus(UserConstants.USER_STATUS_USABLE);
		}

		if (getDao().exists(user, "loginId")) {// 验证重复的登录名
			throw new ApplicationException("用户名已经存在" + user.getLoginId());
		}
		if (getDao().exists(user, "idCard")) {// 验证重复的登录名
			throw new ApplicationException("身份证已经存在" + user.getIdCard());
		}
		if (StringUtils.isNotBlank(user.getEmail())) {
			if (getDao().exists(user, "email")) {
				throw new ApplicationException("您的E-mail地址已经存在,请更换一个.");
			}

		}
		if (encode) { // 密码加密
			user.setPassword(passwordEncoder.encodePassword(user.getPassword(),
					null));
		}
		getDao().saveOrUpdate(user);
		synchronousCache(user, user);
	}

	/** 同步用户缓存 */
	private void synchronousCache(User user, User oldUser) {
		if (userChangeListeners != null) {
			for (UserChangeListener listener : userChangeListeners) {
				listener.onSave(user, oldUser);
			}
		}
	}

	/**
	 * 修改密码
	 * 
	 * @param model
	 *            封装密码的User对象
	 * @param oldPwd
	 *            旧的密码
	 */
	@Transactional
	public void changePassword(User model, String oldPwd) {

		// 获得加密后的密码
		String encodeOldPwd = passwordEncoder.encodePassword(oldPwd, null);
		User user = get(model.getId());

		if (encodeOldPwd.equals(user.getPassword())) { // 判断密码是否一致
			user.setPassword(passwordEncoder.encodePassword(
					model.getPassword(), null));
			getDao().getHibernateTemplate().update(user);
			synchronousCache(user, user);
		} else {
			throw new ApplicationException("旧密码不正确!");
		}
	}

	/**
	 * 密码重置
	 * 
	 * @param user
	 * @param pwd
	 */
	public void resetPwd(User user, String pwd) {
		if (user == null || user.getId() == null) {
			throw new ApplicationException("指定用户为空");
		}
		user = get(user.getId());
		user.setPassword(passwordEncoder.encodePassword(pwd, null));
		getDao().saveOrUpdate(user);
		synchronousCache(user, user);
	}

	/**
	 * 根据用户名更新用户的密码.
	 * 
	 * @param newPwd
	 */
	@Transactional
	public void updatePassByEmail(String email, String loginId, String newPwd) {
		Assert.hasText(email, "E-Mail must not be empty.");

		User user = findObject("from User u where u.loginId=?", loginId);
		if (user == null) {
			throw new ApplicationException(loginId + "不存在");
		}
		if (!StringUtils.equalsIgnoreCase(email, user.getEmail())) {
			throw new ApplicationException("注册邮箱地址不匹配.");
		}
		resetPwd(user, newPwd);
	}

	/** 删除[禁用]用户 */
	@Override
	@Transactional
	public void remove(User user) {
		if (Constants.STATUS_UNAVAILABLE.equals(user.getStatus())) {
			return;
		}
		if (StringUtils.isBlank(user.getLoginId())) {// 确保LoginID存在
			user = get(user.getId());
		}
		if (UserConstants.ADMIN.equals(user.getLoginId())) {
			throw new ApplicationException("不能删除或禁用admin账户。");
		}
		user.setStatus(Constants.STATUS_UNAVAILABLE);
		if (userChangeListeners != null) {
			for (UserChangeListener listener : userChangeListeners) {
				listener.onRemove(user);
			}
		}
	}

	/**
	 * 启用用户
	 * 
	 * @param user
	 */
	@Transactional
	public void unsealUser(User user) {
		if (Constants.STATUS_AVAILABLE.equals(user.getStatus())) {
			return;
		}
		user.setStatus(Constants.STATUS_AVAILABLE);
		synchronousCache(user, user);
	}

	/**
	 * 返回给定用户User所具有的权限[Permission]
	 */
	public List<Permission> findPermissionsByUser(User user) {
		return userDao.findPermissionsByUser(user);
	}

	/** 根据登录名和密码得到User */
	public User getUser(String loginId, String password) {
		String hql = "from User user where user.loginId=? and user.password=?";
		return findObject(hql, new Object[] { loginId, password });
	}

	/**
	 * 根据用户登录名获得User对象
	 * 
	 * @param loginId
	 * @return Instance of User or null.
	 */
	public User getUser(String loginId) {
		return findObject("from User u where u.loginId = ?", loginId);
	}

	/** 得到loginId为{@link #ADMIN_USER}账户 */
	public User getAdmin() {
		return getUser(UserConstants.ADMIN);
	}

	/** 根据email取得用户 */
	public User getUserByEmail(String email) {
		return findObject("from User u where u.email = ?", email);
	}

	/**
	 * 更新用户的登录时间和IP地址
	 */
	@Transactional
	public void updateLoginInformation(User user, String loginIp) {
		if (user != null && user.getId() != null) {

			user.setLastLoginIp(loginIp);
			user.setLastLoginTime(new Date());
			user.setOnline(Constants.YES);
			if (user.getLoginTimes() == null) {
				user.setLoginTimes(1);
			} else {
				user.setLoginTimes(user.getLoginTimes().intValue() + 1);
			}
			update(user);
		}
	}

	/**
	 * 添加用户登录历史记录
	 */
	@Transactional
	public void addUserLoginHistory(User user, String loginIp) {
		if (user != null && user.getId() != null) {
			if (loginIp.equals("0:0:0:0:0:0:0:1")) {
				loginIp = "127.0.0.1";
			}
			UserLoginHistory history = new UserLoginHistory(user, new Date(),
					loginIp, user.getDept());
			getDao().save(history);
		}
	}

	/**
	 * 返回部门以及子部门下的员工信息
	 * 
	 * @param dept
	 *            部门树形列表
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public Map getUserTree(Map dept, String roleName) {
		if (dept.isEmpty()) {
			return dept;
		}
		// 设置部门类型
		dept.put("type", dept.get("type"));
		// 得到部门ID
		Integer deptId = (Integer) dept.get("id");
		List<User> list;
		if (StringUtils.isBlank(roleName)) {
			list = query("from User u where u.dept.id=?", deptId);
		} else {
			list = query(
					"select u from User u inner join u.roles r where u.dept.id=? and r.name=?",
					deptId, roleName);
		}
		// 添加本部门员工
		List children = new ArrayList();
		for (User user : list) {
			Map map = new HashMap();
			map.put("id", user.getId());
			map.put("text", user.getName());
			map.put("type", "user");
			map.put("sex", user.getSex());
			map.put("leaf", true);
			children.add(map);
		}

		// 得到此部门下的所有子部门
		List<Map> childNodes = (List) dept.get("childNodes");
		if (childNodes != null) {
			for (Map map : childNodes) {
				map = getUserTree(map, roleName);
				children.add(map);
			}
		}
		if (!children.isEmpty()) {
			dept.put("children", children);
			dept.put("childNodes", children);
			dept.put("leaf", false);
		} else {
			dept.put("leaf", true);
		}
		return dept;
	}

	/**
	 * 判断某个用户是否在线
	 * 
	 * @return 如果在线(online=1),返回true
	 */
	public boolean isUserOnline(Integer uid) {
		boolean isOnline = false;
		if (uid != null) {
			User user = get(uid);
			if (user != null) {
				isOnline = Constants.YES.equals(user.getOnline());
			}
		}
		return isOnline;
	}

	/**
	 * 根据部门Id获取其对应的用户List（部门负责人）
	 */
	public List<User> getDeptManagers(Integer deptid) {
		String hql = "from User u where u.dept.id = ? and u.type = ? and u.status = ? ";
		return query(hql, new Object[] { deptid, Constants.YES, Constants.YES });
	}

	/**
	 * 根据部门ID获取其部门下所有的部门负责人ids及names
	 */
	public Map<String, String> getDeptManagersMap(Integer deptid) {
		Map<String, String> manager = new HashMap<String, String>();
		StringBuffer auditorIds = new StringBuffer();
		StringBuffer auditorNames = new StringBuffer();
		for (User user : getDeptManagers(deptid)) {// 获得部门的所有复制人，并遍历追加字符串
			auditorIds.append(user.getId()).append(",");
			auditorNames.append(user.getName()).append(",");
		}
		manager.put(FlowConstants.AUDITOR_IDS_KEY, auditorIds.toString());
		manager.put(FlowConstants.AUDITOR_NAMES_KEY, auditorNames.toString());
		return manager;
	}

}
